#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Trace数据处理
"""

import logging
import socket
import uuid

logger = logging.getLogger(__name__)

def extract_services_from_trace(trace_data):
    """
    从trace数据中提取服务信息

    Args:
        trace_data: 完整的trace数据

    Returns:
        list: 服务信息列表，每个服务包含名称、IP地址和端口
    """
    services = {}

    try:
        # 遍历trace数据中的每个span
        for span in trace_data:
            # 提取服务名称
            service_name = None

            # 尝试从不同的字段中提取服务名称
            if 'service' in span and isinstance(span['service'], dict) and 'name' in span['service']:
                service_name = span['service']['name']
            elif 'service_name' in span:
                service_name = span['service_name']
            elif 'service.name' in span.get('tags', {}):
                service_name = span['tags']['service.name']

            # 如果还没有找到，尝试从details中提取
            if not service_name and 'details' in span:
                details = span['details']
                if isinstance(details, dict) and 'service_name' in details:
                    service_name = details['service_name']

            if not service_name:
                continue

            # 提取服务地址信息
            server_address = None
            server_port = None

            # 从标签中提取服务地址和端口
            tags = span.get('tags', {})

            # 尝试从不同的标签中提取服务地址
            for key in ['server.address', 'peer.address', 'http.host', 'server.socket.address']:
                if key in tags:
                    server_address = tags[key]
                    break

            # 尝试从不同的标签中提取服务端口
            for key in ['server.port', 'peer.port', 'server.socket.port']:
                if key in tags:
                    try:
                        server_port = int(tags[key])
                    except (ValueError, TypeError):
                        pass
                    break

            # 如果没有找到地址，尝试从服务名称中提取
            if not server_address:
                # 如果服务名称包含连字符，可能是主机名
                if '-' in service_name or '.' in service_name:
                    try:
                        server_address = socket.gethostbyname(service_name)
                    except socket.gaierror:
                        # 无法解析主机名，使用服务名称作为地址
                        server_address = service_name
                else:
                    # 使用服务名称作为地址
                    server_address = service_name

            # 如果没有找到端口，使用默认值
            if not server_port:
                # 根据服务名称猜测默认端口
                if 'http' in service_name.lower() or 'api' in service_name.lower():
                    server_port = 80
                elif 'mongo' in service_name.lower() or 'db' in service_name.lower():
                    server_port = 27017
                else:
                    server_port = 8080  # 默认微服务端口

            # 将服务信息添加到结果中
            if service_name not in services:
                services[service_name] = {
                    'service_name': service_name,
                    'service_ip': server_address,
                    'service_port': server_port
                }
                logger.info(f"提取到服务: {service_name}, IP: {server_address}, 端口: {server_port}")

    except Exception as e:
        logger.error(f"提取服务信息失败: {e}")

    # 如果没有提取到服务，添加一个模拟服务用于测试
    if not services:
        logger.warning("没有从跟踪数据中提取到服务信息，添加模拟服务用于测试")
        services["test-service"] = {
            'service_name': "test-service",
            'service_ip': "127.0.0.1",
            'service_port': 8080
        }

    return list(services.values())

def extract_requests_from_trace(trace_data, services):
    """
    从 trace 数据中提取请求信息，包括 ingress 和 egress 请求

    Args:
        trace_data: 完整的 trace 数据
        services: 服务信息列表，由 extract_services_from_trace 函数返回

    Returns:
        list: 请求信息列表，每个请求包含 ID、服务 ID、请求类型、请求定义等
    """
    requests = []
    # 创建服务名称到服务ID的映射
    service_name_to_id = {}
    for i, service in enumerate(services):
        if 'service_name' in service:
            service_name_to_id[service['service_name']] = service.get('_id', i)

    try:
        # 遍历 trace 数据中的每个 span
        for span in trace_data:
            # 提取服务名称
            service_name = None

            # 尝试从不同的字段中提取服务名称
            if 'service' in span:
                if isinstance(span['service'], dict) and 'name' in span['service']:
                    service_name = span['service']['name']
                elif isinstance(span['service'], str):
                    service_name = span['service']
            elif 'service_name' in span:
                service_name = span['service_name']
            elif 'service.name' in span.get('tags', {}):
                service_name = span['tags']['service.name']
            elif 'attributes' in span and 'service.name' in span['attributes']:
                service_name = span['attributes']['service.name']

            # 如果还没有找到，尝试从 details 中提取
            if not service_name and 'details' in span:
                details = span['details']
                if isinstance(details, dict) and 'service_name' in details:
                    service_name = details['service_name']

            if not service_name or service_name not in service_name_to_id:
                continue

            service_id = service_name_to_id[service_name]
            attributes = span.get('attributes', {})
            parent_id = span.get('parent_id')

            # 处理 ingress 请求 (入口请求)
            # ingress 请求的特点是没有父 span 或者有 url.path 属性
            if (not parent_id or parent_id == "") or 'url.path' in attributes:
                method = attributes.get('http.request.method')
                path = attributes.get('url.path') or attributes.get('http.route')

                if method and path:
                    request_id = str(uuid.uuid4())
                    requests.append({
                        'request_id': request_id,
                        'service_id': service_id,
                        'request_type': 'ingress',
                        'definition': {
                            'method': method,
                            'url': path
                        }
                    })
                    logger.info(f"提取到入口请求: {method} {path} -> {service_name}")

            # 处理 egress 请求 (出口请求)
            # egress 请求的特点是有 url.full 属性
            if 'url.full' in attributes:
                method = attributes.get('http.request.method')
                url = attributes.get('url.full')

                if method and url:
                    request_id = str(uuid.uuid4())
                    requests.append({
                        'request_id': request_id,
                        'service_id': service_id,
                        'request_type': 'egress',
                        'definition': {
                            'method': method,
                            'url': url
                        }
                    })
                    logger.info(f"提取到出口请求: {method} {url} <- {service_name}")

    except Exception as e:
        logger.error(f"提取请求信息失败: {e}")

    return requests
